package com.gitee.wsl.struct.state

import com.gitee.wsl.api.Cloneable
import com.gitee.wsl.base.IIntRange
import com.gitee.wsl.ext.base.CharExt
import com.gitee.wsl.transform.format.UNICODE_INT_RANGE_TO_STRING


abstract class AST(override vararg val children: AST) : Traversable<AST>, Cloneable<AST> {
    var id = -1;
    var state: NState? = null
    var firstSet: Set<NTransition> = emptySet()
    var followSet: Set<NTransition> = emptySet()
    var nullable: Boolean = false
}

val START_STATE = NState(Int.MIN_VALUE)
val ACCEPT_STATE = NState(Int.MAX_VALUE)

data class NState(val id: Int) {
    override fun toString(): String {
        return if (this == START_STATE) "Start" else if (this == ACCEPT_STATE) "Accept" else id.toString()
    }
}

class NTransition(val input: IInput, val to: NState) {
    override fun toString(): String = input.toString() + "→" + if (to == ACCEPT_STATE) "Accept" else to.id
}


interface IInput {
    fun match(char: Int): Boolean
}

class EOFInput : IInput {
    override fun match(char: Int): Boolean {
        return char == CharExt.EOF
    }

    override fun toString(): String {
        return "EOF"
    }
}

data class SingleInput(val char: Int) : IInput {
    override fun match(char: Int): Boolean {
        return this.char == char
    }

    override fun toString(): String {
        return CharExt.toUnicodeString(char)
    }
}

data class RangeInput(val range: IIntRange) : IInput {

    override fun match(char: Int): Boolean {
        return char in range
    }

    override fun toString(): String {
        return range.toString(UNICODE_INT_RANGE_TO_STRING)
    }
}